#include "odbc/odbc_error.hpp"
#include <vector>
#include <sstream>

namespace odbc
{

// ---------------------------------------------------------------------------------------------------------------------

odbc_error::odbc_error( SQLRETURN res_code, SQLHANDLE handle, int handle_type)
	: result_code_( res_code)
{
	this->fetch_diagnostics( handle, handle_type);
	this->build_error_message();
}

// ---------------------------------------------------------------------------------------------------------------------

void odbc_error::fetch_diagnostics( SQLHANDLE handle, SQLSMALLINT handle_type)
{
	SQLCHAR sqlStat[6];
	SQLINTEGER nativeError;
	SQLSMALLINT recNo = 1;
	SQLRETURN retCode = SQL_SUCCESS;
	do
	{
		SQLSMALLINT messageLen;
		// obtain the message length
		retCode = SQLGetDiagRec(
			handle_type,
			handle,
			recNo,
			sqlStat,
			&nativeError,
			NULL,
			0,
			&messageLen);
		if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO)
		{
			break;
		}
		std::vector< SQLCHAR> messageBuffer( messageLen + 1, 0);
		// get the error message and all the other stuff.
		retCode = SQLGetDiagRec(
			handle_type,
			handle,
			recNo,
			sqlStat,
			&nativeError,
			static_cast< SQLCHAR*>(
				&messageBuffer[0]),
				SQLSMALLINT( messageBuffer.size()),
			&messageLen);
		if( retCode == SQL_SUCCESS || retCode == SQL_SUCCESS_WITH_INFO)
		{
			// add the diagnostic record
			diagnostics_.push_back(
				details::diagnostic_record(
					std::string( sqlStat, sqlStat + 5),
					int( nativeError),
					std::string( messageBuffer.begin(), messageBuffer.end())));
		}
		++recNo;
	}
	while( retCode == SQL_SUCCESS);
}

// ---------------------------------------------------------------------------------------------------------------------

void odbc_error::build_error_message()
{
	std::ostringstream msgStrm;
	msgStrm << "Returned code: " << result_code_ << std::endl;
	for( diag_rec_collection::iterator i = diagnostics_.begin();
		 i != diagnostics_.end();
		 ++i)
	{
		msgStrm << "Error " << i->native_error() << ": ["
			<< i->sql_state() << "] " << i->error_message() << std::endl;
	}
	error_message_ = msgStrm.str();
}

// ---------------------------------------------------------------------------------------------------------------------

const char* odbc_error::what() const throw()
{
	return error_message_.c_str();
}

} // namespace odbc
